home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / prog / cport2.zip / COMDEMO.C next >
C/C++ Source or Header  |  1993-04-09  |  27KB  |  1,141 lines

  1. /* 
  2. // COMDEMO.C
  3. //
  4. // Serial communications demo program for the Cport communications library.
  5. // 
  6. // Copyright (c) 1993 Bri Productions
  7. //
  8. */
  9.  
  10. #include "cport.h"
  11. #include "xmodem.h"
  12. #include <conio.h>
  13. #include <stdlib.h>      
  14. #include <dos.h>
  15. #include <bios.h>
  16. #include <ctype.h>
  17. #include <stdio.h>
  18.  
  19.  
  20. /*
  21. //-------------------------------------
  22. //
  23. // Microsoft portability
  24. //
  25. //-------------------------------------
  26. */
  27. #if M_I86
  28.  
  29. #include <stdarg.h>
  30. #include <time.h>
  31. #include <graph.h>
  32.  
  33. #define    BLUE         1
  34. #define  LIGHTGRAY 7
  35.  
  36. #define     bioskey(a)         _bios_keybrd(a)
  37. #define    gotoxy(x,y)         _settextposition((short)(y), (short)(x))
  38. #define    clrscr()             _clearscreen(_GWINDOW)
  39. #define    textattr(a)         _settextcolor((short)((a)&0xf)); _setbkcolor((short)((a)>>4))
  40. #define    window(a,b,c,d) _settextwindow((short)(b),(short)(a),(short)(d),(short)(c))
  41. #define  cputs(s)             _outtext(s)
  42.  
  43. int  wherex (void);
  44. int  wherey (void);
  45. void delay  (clock_t milliseconds);
  46. void clreol (void);
  47.  
  48. #endif
  49.  
  50. /* 
  51. //-------------------------------------
  52. //
  53. // Queue sizes and thresholds
  54. //
  55. //-------------------------------------
  56. */
  57. #define  TXQ      4096
  58. #define  RCVQ     4096
  59. #define  THRESH   (RCVQ * 3 / 4)
  60.  
  61.  
  62. /*
  63. //-------------------------------------
  64. // 
  65. // numbers of parameters
  66. //
  67. //-------------------------------------
  68. */
  69. #define  NUM_COM     4             
  70. #define  NUM_BAUD    9
  71. #define  NUM_MODE    2
  72. #define  NUM_HND     4
  73.  
  74.  
  75. /*
  76. //-------------------------------------
  77. // 
  78. // scan codes
  79. //
  80. //-------------------------------------
  81. */
  82. #define  A     0x1E00
  83. #define  B     0x3000
  84. #define  C     0x2E00
  85. #define  D     0x2000
  86. #define  E     0x1200
  87. #define  F     0x2100
  88. #define  G     0x2200
  89. #define  H     0x2300
  90. #define  I     0x1700
  91. #define  M     0x3200
  92. #define  N     0x3100
  93. #define  O     0x1800
  94. #define  P     0x1900
  95. #define  R     0x1300
  96. #define  S     0x1F00
  97. #define  W     0x1100
  98. #define  X     0x2D00
  99. #define  PGDN  0x5100
  100. #define  PGUP  0x4900
  101.  
  102.  
  103. #define COM3A  PORT2|IRQ5
  104.  
  105.  
  106. /*
  107. //-------------------------------------
  108. //
  109. // text attributes
  110. //
  111. //-------------------------------------
  112. */
  113. #define  NORM  0x07
  114. #define  BOLD  0x08
  115. #define  FAINT 0xF7
  116. #ifndef  BLINK
  117. #define  BLINK 0x80
  118. #endif
  119. #define  REVRS 0x77
  120. #define  ESC   0x1b
  121.  
  122.  
  123. /*
  124. //-------------------------------------
  125. //
  126. // parameter constants
  127. //
  128. //-------------------------------------
  129. */
  130. const unsigned id[]    = { COM1, COM2, COM3A, COM4 };
  131. const int      baud[]   = { B115200, B57600, B38400, B19200, 
  132.                             B9600, B4800, B2400, B1200, B300 };
  133. const byte     mode[]   = { W8|S1|NONE, W7|S1|EVEN };
  134. const byte     hndshk[] = { OFF ,SOFT, HARD, HARD|SOFT };
  135.  
  136. /*
  137. //-------------------------------------
  138. //
  139. // parameter indexes
  140. //
  141. //-------------------------------------
  142. */
  143. struct indx{
  144.    byte id;
  145.    byte baud;
  146.    byte mode;
  147.    byte ansi;
  148.    byte hndshk;
  149.    byte lf;
  150.  byte echo;
  151.    }indx = { 0, 3, 0, 1, 0, 0, 0 };
  152.  
  153.  
  154. /*
  155. //-------------------------------------
  156. //
  157. // parameter messages
  158. //
  159. //-------------------------------------
  160. */
  161. struct{
  162.    char *id    [NUM_COM ];    
  163.    char *baud  [NUM_BAUD];   
  164.    char *mode  [NUM_MODE];     
  165.    char *ansi  [2];
  166.    char *hndshk[NUM_HND];
  167.    char *lf    [2];
  168.    }msg={   
  169.             { "COM1", "COM2", "COM3", "COM4" },
  170.             { "115k", "57600", "38400", "19200", "9600", 
  171.               "4800", "2400", "1200", "300" },
  172.             { "8-1-N", "7-1-E" }, 
  173.             { "TTY", "ANSI" },
  174.             { "NONE", "SOFT", "HARD", "BOTH" },
  175.             { "  ", "LF" }
  176.         };
  177.  
  178.  
  179. /*
  180. //-------------------------------------
  181. //
  182. // screen coordinates
  183. //
  184. //-------------------------------------
  185. */
  186. static int x = 1;                      /* cursor location               */
  187. static int y = 1;
  188. static byte attrib = NORM;             /* present text attribute        */
  189. #define  ERR_X    41                   /* error message x coordinate    */
  190. #define  STAT_X   60                   /* status message x coordinate   */
  191.  
  192.  
  193. /*
  194. //-------------------------------------
  195. //
  196. // function prototypes
  197. //
  198. //-------------------------------------
  199. */
  200. static void     Init        (void);
  201. static void     Uninit      (void);
  202. static void     NewParam    (void);
  203. static void     Ansi        (void);
  204. static void     CheckError  (void);
  205. static void     CheckStatus (void);
  206. static void     Upload      (void);
  207. static void     Download    (void);
  208. static int      callback   (int msg, unsigned param);
  209. static void     put_ch  (char c);
  210.  
  211.  
  212.  
  213. char  *Xmsg[] = { "\r\ntransfer successful",
  214.                   "\r\nfile error",
  215.                   "\r\ntransfer canceled",
  216.                   "\r\nmemory error"
  217.                };
  218.  
  219. struct C_param param;
  220. COM com;
  221.  
  222. /*
  223. //-------------------------------------
  224. //
  225. // main()
  226. //
  227. //-------------------------------------
  228. */
  229. void main(void)  
  230. {     
  231. char c;
  232. unsigned key;
  233. byte dtr = ON;
  234.  
  235.  
  236.       /* initialize  */
  237.  
  238.    Init();   
  239.  
  240.    while(1)
  241.    {
  242.       
  243.          /* Poll the keyboard buffer for available keystrokes.       */
  244.          /* Meanwhile, the receive queue is checked for available    */
  245.          /* characters, check for errors and check the modem status  */
  246.  
  247.       while(!bioskey(1))         
  248.       {
  249.  
  250.             /* If a character(s) is available in the receive queue,  */
  251.             /* fetch it. If it is and escape character, it must be   */
  252.             /* check to see if it is the start of an ansi sequence.  */
  253.             /* Otherwise the cursor position is updated, and the     */
  254.             /* character is printed.                                 */
  255.          
  256.          if(ComLenRx(com))        
  257.          {
  258.             c = ComGetc(com);      
  259.  
  260.             if(c == ESC && indx.ansi)        
  261.             {
  262.                Ansi();  
  263.                gotoxy(x, y);
  264.                continue;
  265.             }
  266.  
  267.           put_ch(c);            
  268.  
  269.          }
  270.  
  271.  
  272.             /* Check for errors and changes in the modem status   */
  273.  
  274.          CheckError();       
  275.          CheckStatus();      
  276.       }
  277.    
  278.  
  279.          /* When a key is pressed, the key is fetched, and the    */
  280.          /* keyboard flags are checked to see if the alt key was  */
  281.          /* also pressed. If the alt key was pressed, we must     */
  282.          /* check if the key is a valid command, and if so        */
  283.          /* process it accordingly                                */
  284.  
  285.       key = bioskey(0);                   
  286.       if(!(key & 0x00ff))  
  287.       {
  288.          switch(key)                      
  289.          {
  290.  
  291.                /* exit  */
  292.  
  293.             case X:                  
  294.                Uninit();
  295.  
  296.  
  297.                /* Next com port  */
  298.  
  299.             case C:                  
  300.                ComParam(com, ¶m);
  301.                ComClose(com);
  302.                do
  303.                {
  304.                   indx.id++;             
  305.                   indx.id %= NUM_COM;    
  306.                   param.id = id[indx.id];
  307.                }
  308.                while((com = ComOpenS(¶m)) == NULL);
  309.                NewParam(); 
  310.                break;
  311.  
  312.  
  313.                /* Next baud rate */
  314.  
  315.             case B:                  
  316.                indx.baud++;            
  317.                indx.baud %= NUM_BAUD;  
  318.                ComBaud(com, baud[indx.baud]);
  319.                NewParam(); 
  320.                break;
  321.  
  322.  
  323.                /* Next word length  */
  324.  
  325.             case M:                    
  326.                indx.mode++;            
  327.                indx.mode %= NUM_MODE;  
  328.                ComMode(com, mode[indx.mode]);
  329.                NewParam(); 
  330.                break;
  331.  
  332.  
  333.                /* Toggle ansi terminal */
  334.  
  335.             case A:
  336.                indx.ansi ^= 1;
  337.                NewParam();
  338.                break;
  339.  
  340.  
  341.                /* Next handshake scheme   */
  342.  
  343.             case H:
  344.                indx.hndshk++;
  345.                indx.hndshk %= NUM_HND;
  346.                ComHandshake(com, hndshk[indx.hndshk], THRESH);
  347.                NewParam();
  348.                break;
  349.  
  350.  
  351.               /* Echo */
  352.  
  353.             case E:
  354.                indx.echo ^= 1;
  355.                break;
  356.  
  357.  
  358.                /* Toggle LF append  */
  359.  
  360.             case N:
  361.                indx.lf ^= 1;
  362.                NewParam();
  363.                break;
  364.  
  365.                /* Initialize hayes modem  */
  366.  
  367.             case I:                    
  368.                ComPuts(com, "ATZ\r\n");         
  369.                break;
  370.  
  371.  
  372.                /* Hayes modem dial command   */
  373.  
  374.             case D:                    
  375.                ComPuts(com, "ATDT");           
  376.                break;
  377.  
  378.  
  379.                /* Hayes modem hang up command   */
  380.  
  381.             case G:                    
  382.                ComPuts(com, "+++");
  383.                delay(3000);
  384.                ComPuts(com, "ATH0\r\n");
  385.                break;
  386.  
  387.             case PGUP:
  388.                Upload();
  389.                break;
  390.  
  391.             case PGDN:
  392.                Download();
  393.                break;
  394.  
  395.             case R:
  396.                dtr ^= 1;
  397.                ComDtr(com, dtr);
  398.                break;
  399.  
  400.             default:                   
  401.                continue;
  402.          }
  403.       }
  404.  
  405.  
  406.          /* If the key was not a command, put the character in the   */
  407.          /* transmit queue. If the character is a carriage return,   */
  408.          /* append a line feed to it just in case.                   */
  409.  
  410.       else
  411.       {
  412.          ComPutc(com, (char)key);       
  413.    if(indx.echo)
  414.     put_ch((char)key);
  415.          CheckStatus();      
  416.          CheckError();       
  417.       }
  418.    }
  419. }
  420.  
  421.  
  422. /*
  423. //-------------------------------------
  424. //
  425. // Modified putch()
  426. //
  427. //-------------------------------------
  428. */
  429. void put_ch(char c)
  430. {
  431.  
  432.      gotoxy(x, y);
  433.     putch(c);
  434.  
  435.    if(c == '\r' && indx.lf)
  436.          putch('\n');
  437.  
  438.    if(c == '\b')
  439.       printf(" \b");
  440.  
  441.    x = wherex();        
  442.    y = wherey();
  443.  
  444. #ifdef M_I86
  445.     if(x == 1 && y == 25)
  446.         _scrolltextwindow(1);
  447. #endif
  448. }
  449.  
  450.  
  451. /*
  452. //-------------------------------------
  453. //
  454. // Initialize
  455. //
  456. //-------------------------------------
  457. */
  458. void Init(void)
  459. {
  460. FILE *fp;
  461.  
  462.  
  463.  
  464.       /* If an initialization file exists, load it.   */
  465.  
  466.    fp = fopen("comdemo.ini", "rb");
  467.    if(fp)
  468.       fread(&indx, sizeof(struct indx), 1, fp);
  469.  
  470.  
  471.  
  472.       /* Set up the screen */
  473.  
  474.    clrscr();                        
  475.    textattr(BLUE|(LIGHTGRAY<<4));   
  476.    gotoxy(1,25);                    
  477.    cprintf(" %4s │%5s %s │ %-4s │ %-4s │ %2s │"
  478.            " no errors    │ CTS=  DSR=   RI=  DCD=  ",
  479.                                     msg.id[indx.id],
  480.                                     msg.baud[indx.baud],
  481.                                     msg.mode[indx.mode],
  482.                                     msg.ansi[indx.ansi],
  483.                                     msg.hndshk[indx.hndshk],
  484.                                     msg.lf[indx.lf]);
  485.  
  486.  
  487.       /* Initialize the serial port to the default parameters,    */
  488.       /* set the timeout and set the DTR and RTS lines.           */
  489.  
  490.    com = ComOpen(id[indx.id], baud[indx.baud], mode[indx.mode], RCVQ, TXQ);
  491.  
  492.  
  493.       /* restore the normal screen  */
  494.  
  495.    textattr(LIGHTGRAY);               
  496.    window(1,1,80,24);                 
  497. }
  498.  
  499.  
  500. /*
  501. //-------------------------------------
  502. //
  503. // terminate
  504. //
  505. //-------------------------------------
  506. */
  507. void Uninit(void)
  508. {
  509. FILE *fp;
  510.  
  511.  
  512.       /* Store the present parameters in an .ini file so the program */
  513.       /* will remember next time it is executed.                     */
  514.  
  515.    fp = fopen("comdemo.ini", "wb");
  516.    if(fp)
  517.       fwrite(&indx, sizeof(struct indx), 1, fp);
  518.  
  519.  
  520.    ComClose(com);             
  521.    system("cls");     
  522.    puts("\n╒═════════════════════════════════════════════════════════════════════════════╕"
  523.         "\n│             Cport v2.0  -  Copyright (c) 1993 Bri Productions               │"
  524.         "\n├─────────────────────────────────────────────────────────────────────────────┤"
  525.         "\n│ Bri Productions, P.O. Box 7121, Fremont, CA 94537-7121, USA, (510) 794-0616 │"
  526.         "\n╘═════════════════════════════════════════════════════════════════════════════╛"
  527.         );  
  528.    exit(0);                
  529. }
  530.  
  531.  
  532. /*
  533. //-------------------------------------
  534. //
  535. // new parameter
  536. //
  537. //-------------------------------------
  538. */
  539. void NewParam(void)
  540. {
  541.  
  542.       /* Update the status line with the new parameters  */
  543.  
  544.    window(1,25, 80, 25);            
  545.    textattr(BLUE|(LIGHTGRAY<<4));   
  546.    cprintf(" %4s │%5s %s │ %-4s │ %-4s │ %s │", 
  547.                                     msg.id[indx.id],
  548.                                     msg.baud[indx.baud],
  549.                                     msg.mode[indx.mode],
  550.                                     msg.ansi[indx.ansi],
  551.                                     msg.hndshk[indx.hndshk],
  552.                                     msg.lf[indx.lf]);
  553.  
  554.  
  555.       /* restore the normal screen  */
  556.  
  557.    textattr(attrib);                
  558.    window(1,1,80,24);               
  559.  gotoxy(x, y);
  560. }
  561.  
  562.  
  563. /*
  564. //-------------------------------------
  565. //
  566. // ansi control sequence 
  567. //
  568. //-------------------------------------
  569. */
  570. void Ansi(void)
  571. {
  572. unsigned key;
  573. char c;
  574. char str[10];
  575. int Pn[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  576. int i=0,p=0;
  577. static int oldx=1;
  578. static int oldy=1;
  579.    
  580.  
  581.       /* While we are waiting for the next character, keep   */
  582.       /* checking for keys.                                  */
  583.  
  584.  
  585.    while((c = ComGetc(com)) == 0) 
  586.  
  587.    if(bioskey(1))            
  588.    {
  589.       key = bioskey(0);      
  590.       ComPutc(com, (char)key);   
  591.    }
  592.  
  593.  
  594.       /* If the next character is a '[' it is probably an ansi    */
  595.       /* sequence. If the next character is not a '[', print the  */
  596.       /* previous escape character followed by the new character. */
  597.  
  598.    if(c != '[')                  
  599.    {
  600.       cprintf("\x1b%c",c);       
  601.       return;
  602.    }
  603.  
  604.    while(1)                            
  605.    {
  606.  
  607.       /* Read the rest of the ansi sequence, while also checking  */
  608.       /* for keys.                                                */
  609.  
  610.       while((c = ComGetc(com)) == 0) 
  611.    
  612.          if(bioskey(1))         
  613.          {
  614.             key = bioskey(0);           
  615.             ComPutc(com, (char)key);        
  616.          }
  617.  
  618.  
  619.          /* If the character is numeric, store it still it it's   */
  620.          /* ascii form                                            */
  621.  
  622.       if(isdigit(c))                      
  623.       {
  624.          *(str+i++) = c;                  
  625.          continue;
  626.       }
  627.  
  628.  
  629.          /* When no more numeric characters are received, terminate  */
  630.          /* the string and convert it to an integer, storing it in   */
  631.          /* the parameter queue.                                     */
  632.  
  633.       *(str+i) = '\0';                
  634.       i=0;                            
  635.       Pn[p++] = atoi(str);            
  636.  
  637.  
  638.          /* Check for the ';' delimiter   */
  639.  
  640.       if(c == ';')                    
  641.          continue;   
  642.  
  643.  
  644.          /* When no more numeric parameters are received, the     */
  645.          /* command should be next. Now we can actually process   */
  646.          /* the command using the stores parameters               */
  647.  
  648.       else
  649.       {
  650.          switch(c)              
  651.          {
  652.  
  653.  
  654.                /* (CUP) set cursor position  */
  655.          
  656.             case 'H':            
  657.             case 'F':
  658.                y = Pn[0] ? Pn[0] : 1;        
  659.                x = Pn[1] ? Pn[1] : 1;
  660.                return;
  661.  
  662.  
  663.                /* (CUU) cursor up   */
  664.    
  665.             case 'A':            
  666.                y -= Pn[0];       
  667.                if(y < 1)         
  668.                   y = 1;
  669.                return;
  670.  
  671.  
  672.                /* (CUD) cursor down */
  673.  
  674.             case 'B':            
  675.                y += Pn[0];       
  676.                if(y > 24)        
  677.                   y = 24;
  678.                return;
  679.  
  680.  
  681.                /* (CUF) cursor forward */
  682.  
  683.             case 'C':            
  684.                x += Pn[0];       
  685.                if(x >80)         
  686.                   x = 80;
  687.                return;
  688.  
  689.  
  690.                /* (CUB) cursor backward   */
  691.  
  692.             case 'D':             
  693.                x -= Pn[0];       
  694.                if(x < 1)
  695.                   x = 1;
  696.                return;
  697.                
  698.  
  699.                /* (SCP) save cursor position */
  700.  
  701.             case 's':            
  702.                oldx = x;         
  703.                oldy = y;
  704.                return;
  705.  
  706.  
  707.                /* (RCP) restore cursor position */
  708.  
  709.             case 'u':            
  710.                x = oldx;
  711.                y = oldy;
  712.                return;
  713.  
  714.  
  715.                /* clear screen   */
  716.  
  717.             case 'J':            
  718.                if(Pn[0] == 2)
  719.                {
  720.                   clrscr();
  721.                   x=1;
  722.                   y=1;
  723.                }
  724.                else 
  725.                {
  726.                   window(1,wherey(),80,24);                 
  727.                   clrscr();
  728.                   window(1,1,80,24);                 
  729.                   gotoxy(x, y);
  730.                }
  731.                return;
  732.  
  733.  
  734.                /* (EL) erase line   */
  735.  
  736.             case 'K':            
  737.                clreol();
  738.                return;
  739.          
  740.  
  741.                /* An attribute command is more elaborate than the    */
  742.                /* others because it may have many numeric parameters */
  743.  
  744.             case 'm':                        
  745.                for(i=0; i<p; i++)            
  746.                {
  747.  
  748.  
  749.                      /* values from 30 to 37 define the foreground color   */
  750.  
  751.                   if(Pn[i] >= 30 && Pn[i] <= 37)  
  752.                   {
  753.                      attrib &= 0xf8;
  754.                      attrib |= (Pn[i] - 30);
  755.                   }
  756.  
  757.  
  758.                      /* values from 40 to 47 define the background color   */
  759.  
  760.                   if(Pn[i] >= 40 && Pn[i] <= 47)  
  761.                   {
  762.                      attrib &= 0x8f;
  763.                      attrib |= ((Pn[i] - 40) << 4);
  764.                   }
  765.  
  766.  
  767.                      /* values from 0 to 7 define the other attributes   */
  768.  
  769.                   if(Pn[i] >= 0 && Pn[i] <= 7)    
  770.                      switch(Pn[i])
  771.                      {
  772.  
  773.                         case 0:              
  774.                            attrib = NORM;
  775.                            break;
  776.  
  777.                         case 1:              
  778.                            attrib |= BOLD;
  779.                            break;
  780.  
  781.                         case 2:              
  782.                            attrib &= FAINT;
  783.                            break;
  784.  
  785.                         case 5:              
  786.                         case 6:
  787.                            attrib |= BLINK;
  788.                            break;
  789.  
  790.                         case 7:                    
  791.                            attrib ^= REVRS;
  792.                            break;
  793.  
  794.                         default:
  795.                            attrib = NORM;
  796.                      }
  797.                }
  798.  
  799.  
  800.                /* The red and blue bits in the ansi standard are     */
  801.                /* reversed relative to the IBM. Therefore, before we */
  802.                /* set the new attributes, if these bits are in       */
  803.                /* opposite states toggled. This must be done for     */
  804.                /* both the foreground and background.                */
  805.                                             
  806.                if((attrib & 0x05) == 0x04 || (attrib & 0x05) == 0x01)
  807.                   attrib ^= 0x05;
  808.                                             
  809.                if((attrib & 0x50) == 0x40 || (attrib & 0x50) == 0x10)
  810.                   attrib ^= 0x50;
  811.  
  812.                textattr(attrib);           
  813.  
  814.             default:
  815.                return;
  816.          }
  817.       }
  818.    }
  819. }
  820.  
  821.  
  822. /* 
  823. //-------------------------------------         
  824. //
  825. // check for errors
  826. //
  827. //-------------------------------------         
  828. */
  829. void CheckError(void)
  830. {
  831. unsigned comerror;         
  832. static unsigned last_error = 0;
  833. static int err_flg = 0;
  834. char *errmsg[]= { { "no errors    " },
  835.                   { "break detect " }, 
  836.                   { "frame error  " },
  837.                   { "parity error " },
  838.                   { "overrun      " },
  839.                   { "rx overflow " }, 
  840.                   { "tx overflow  " } 
  841.                   };
  842.  
  843.    comerror = ComError(com);      
  844.  
  845.  
  846.       /* Check if the error code has changed since the last call.    */
  847.       /* if it has not, there is no need to update the status line.  */
  848.       /* If the error code has changed, the error conditions are     */
  849.       /* checked in the order of their priority                      */
  850.  
  851.    if(comerror != last_error)       
  852.    {
  853.       last_error = comerror;        
  854.  
  855.       if(comerror & BREAK)              
  856.          err_flg = 1;                     
  857.       
  858.       else if(comerror & FRAMING)       
  859.          err_flg = 2;                     
  860.  
  861.       else if(comerror & PARITY)        
  862.          err_flg = 3;                     
  863.  
  864.       else if(comerror & OVERUN)       
  865.          err_flg = 4;                     
  866.  
  867.       else if(comerror & RXFULL)      
  868.          err_flg = 5;                     
  869.  
  870.       else if(comerror & TXFULL)       
  871.          err_flg = 6;                     
  872.    
  873.       else                             
  874.          err_flg = 0;
  875.  
  876.  
  877.          /* Update the status line with the new information   */
  878.  
  879.       window(1,25, 80, 25);          
  880.       textattr(BLUE|(LIGHTGRAY<<4)); 
  881.       gotoxy(ERR_X,1);
  882.       cprintf(errmsg[err_flg]);
  883.  
  884.  
  885.          /* restore the normal screen  */
  886.  
  887.       textattr(attrib);              
  888.       window(1,1,80,24);              
  889.     gotoxy(x, y);
  890.    }
  891. }
  892.  
  893.  
  894. /* 
  895. //-------------------------------------
  896. //
  897. // check modem status
  898. //
  899. //-------------------------------------
  900. */
  901. void CheckStatus(void)
  902. {
  903. unsigned status;
  904. static unsigned last_status = 1;   
  905. int i;
  906.  
  907.    status = ComStatus(com);
  908.  
  909.  
  910.       /* Check if the modem status has changed since the last call.  */
  911.       /* if it has not, there is no need to update the status line.  */
  912.       /* If the modem status has changed, each bit is checked for    */
  913.       /* it's condition and printed on the status line               */
  914.  
  915.    if(status != last_status)
  916.    {
  917.       last_status = status;
  918.       window(1,25, 80, 25);                  
  919.       textattr(BLUE|(LIGHTGRAY<<4));         
  920.  
  921.  
  922.          /* On each iteration, i = the x coordinate in the status */
  923.          /* line. The bits are checked for left to right. The     */
  924.          /* statement !!(status & 0x10) resolves to 1 if the bit  */
  925.          /* is set or 0 if the bit is clear. By adding 0x30 the   */
  926.          /* 1 or 0 is converted to an ascii character             */
  927.  
  928.       for(i=STAT_X; i<STAT_X+6*4; i+=6)
  929.       {
  930.          gotoxy(i,1);                       
  931.          cprintf("%c", !!(status & 0x10) + 0x30);   
  932.          status >>= 1;                      
  933.       }
  934.  
  935.  
  936.          /* restore the normal screen  */
  937.  
  938.       textattr(attrib);      
  939.       window(1,1,80,24);     
  940.     gotoxy(x, y);
  941.    }
  942. }
  943.  
  944.  
  945. /* 
  946. //-------------------------------------
  947. //
  948. // Upload a file
  949. //
  950. //-------------------------------------
  951. */
  952. void Upload(void)
  953. {
  954. char  filename[83];
  955. int   rv;
  956.  
  957.    cputs("\r\n");
  958.    x = wherex();
  959.    y = wherey();
  960.  
  961.    *filename = 80;
  962.    cputs("File name > ");
  963.    cgets(filename);
  964.    
  965.    rv = XmodemTx(com, filename + 2, callback);
  966.  
  967.    clreol();
  968.    cputs(*(Xmsg + rv));
  969.  
  970.    cputs("\r\n");
  971.    x = wherex();
  972.    y = wherey();
  973. }
  974.  
  975.  
  976. /* 
  977. //-------------------------------------
  978. //
  979. // Download a file
  980. //
  981. //-------------------------------------
  982. */
  983. void Download(void)
  984. {
  985. char  filename[83];
  986. int   rv;
  987.  
  988.  
  989.    cputs("\r\n");
  990.    x = wherex();
  991.    y = wherey();
  992.  
  993.    *filename = 80;
  994.    cputs("File name for your computer > ");
  995.    cgets(filename);
  996.    
  997.    rv = XmodemRx(com, filename + 2, callback);
  998.  
  999.    clreol();
  1000.    cputs(*(Xmsg + rv));
  1001.  
  1002.    cputs("\r\n");
  1003.    x = wherex();
  1004.    y = wherey();
  1005.  
  1006. }
  1007.  
  1008.  
  1009. /*
  1010. //-------------------------------------
  1011. //
  1012. // Xmodem callback function
  1013. //
  1014. //-------------------------------------
  1015. */
  1016. int callback(int msg, XPARAM param)
  1017. {
  1018. static retry = 10;
  1019. const char *_err_txt;
  1020. static const char *err_txt[] =   {  
  1021.                                     "OVER RUN",
  1022.                                     "BAD BLOCK",
  1023.                                     "BAD BLOCK CHECK",
  1024.                                     "TIME OUT",
  1025.                                     "TRANSFER CANCELED"
  1026.                                  };
  1027.  
  1028.    switch(msg)
  1029.    {
  1030.       case XM_IDLE:
  1031.          break;
  1032.  
  1033.       case XM_START:
  1034.          cprintf("\r\nWaiting...");
  1035.          break;
  1036.  
  1037.       case XM_BLOCKCHECK:
  1038.          cprintf("\r\nblock check:%s\r\n", param == 0 ? "CHECKSUM" : "CRC");
  1039.          break;
  1040.  
  1041.       case XM_BLOCK:
  1042.          if(retry < 10)
  1043.          {
  1044.             retry = 10;
  1045.             putchar('\n');
  1046.          }
  1047.          cprintf("\rblock:%d bytes: %ld", param, ((long)param) << 7);
  1048.          break;
  1049.  
  1050.       case XM_EOT:
  1051.          cprintf("\r\nEOT");
  1052.          break;
  1053.  
  1054.       case XM_DONE:
  1055.          break;
  1056.  
  1057.       case XM_ERROR:
  1058.          if(param & OVERUN)
  1059.             _err_txt = err_txt[0];
  1060.          else
  1061.             _err_txt = err_txt[param >> 12];
  1062.          cprintf("\r\nERROR:%s", _err_txt);
  1063.          if(retry-- == 0)
  1064.             return(1);
  1065.    }
  1066.  
  1067.    if(kbhit())
  1068.    {
  1069.       if(getch() == 0x1b)
  1070.          return(1);
  1071.    }
  1072.    return(0);
  1073. }
  1074.  
  1075.  
  1076.  
  1077. /*
  1078. //-------------------------------------
  1079. //
  1080. // Microsoft portability
  1081. //
  1082. //-------------------------------------
  1083. */
  1084. #if M_I86
  1085.  
  1086.  
  1087. int wherex(void)
  1088. {
  1089. byte    rv;
  1090.  
  1091.     _asm    {
  1092.                 mov    bh,0
  1093.                 mov    ah,3
  1094.                 int    10h
  1095.                 inc    dl
  1096.                 mov    rv,dl
  1097.             }
  1098.     return(rv);
  1099. }
  1100.  
  1101. int wherey(void)
  1102. {
  1103. byte    rv;
  1104.  
  1105.     _asm    {
  1106.                 mov    bh,0
  1107.                 mov    ah,3
  1108.                 int    10h
  1109.                 inc    dh
  1110.                 mov    rv,dh
  1111.             }
  1112.     return(rv);
  1113. }
  1114.  
  1115. void delay  (clock_t milliseconds)
  1116. {
  1117.     milliseconds += clock();
  1118.     while(clock() < milliseconds);
  1119. }
  1120.  
  1121. void clreol(void)
  1122. {
  1123.     cprintf("%*c", 80 - wherex() - 1, ' ');
  1124. }
  1125.  
  1126. int cprintf(const char *fmt, ...)
  1127. {
  1128. va_list list;
  1129. int rv;
  1130. char buf[129];
  1131.  
  1132.    va_start(list, fmt);
  1133.    rv = vsprintf(buf, fmt, list);
  1134.    va_end(list);
  1135.     _outtext(buf);
  1136.    return(rv);
  1137. }
  1138.  
  1139. #endif
  1140.  
  1141.